package xyz.lwm.lazycat.aop.support;

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import xyz.lwm.lazycat.aop.InvocationHandler;
import xyz.lwm.lazycat.utility.ThrowableUtil;

import java.lang.reflect.Method;

/**
 * method interceptor
 *
 * @author lwm
 */
public class Interceptor {

    // original target object
    private final Object target;

    // method interceptors
    private final InvocationHandler[] handlers;

    Interceptor(Object target, InvocationHandler[] handlers) {
        this.target = target;
        this.handlers = handlers;
    }

    /**
     * intercept method by invocation handlers
     *
     * @param method method
     * @param args arguments
     * @return result
     * @throws Throwable if any error
     */
    @RuntimeType
    public Object intercept(@Origin Method method, @AllArguments Object[] args) throws Throwable {
        Call.Ref<Object[]> argsRef = new Call.Ref<>(args);
        Call.Ref<Object> resultRef = new Call.Ref<>();
        // original invocation, 即调用业务的 invocation
        Call call = new Call(() -> {
            try {
                return method.invoke(target, argsRef.get());
            } catch (Throwable e) {
                // invocation exception、
                // UndeclaredThrowableException、
                // runtime exception 需解包, 其内部异常才是真正的异常
                throw ThrowableUtil.unwrap(e);
            }
        }, target, method, argsRef, resultRef);
        // wrap invocation for handlers
        for (InvocationHandler handler : handlers) {
            // wrap to new invocation
            call = call.wrap(handler);
        }
        // invoke
        call.invoke();
        return resultRef.get();
    }

}